/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

//定义promise状态常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class myPromise {
    constructor(executor) {
        try {
            executor(this.resolve,this.reject)
        }catch (e) {
            this.reject(e)
        }
    }

    value = undefined
    reason = undefined
    successCallback = []
    failedCallback = []
    status = PENDING

    resolve = (value)=> {
        //判断如果当前状态已改变 就不再执行下面的代码
        if(this.status!==PENDING) return
        this.status = FULFILLED
        this.value = value
        // this.successCallback && this.successCallback(this.value)
        while (this.successCallback.length) this.successCallback.shift()()
    }

    reject = (reason)=> {
        if(this.status!==PENDING) return
        this.status = REJECTED
        this.reason = reason
        // this.failedCallback && this.failedCallback(this.value)
        //判断失败会回调是否有值并执行
        while (this.failedCallback.length) this.failedCallback.shift()()
    }

    then(successCallback,failedCallback) {
        successCallback = successCallback ? successCallback : value => value
        failedCallback = failedCallback ? failedCallback : reason => {throw reason}
        let promise2 = new myPromise((resolve, reject) => {
            if(this.status===FULFILLED) {
                //为了获取对应的promise2，使用延迟
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value);
                        //根据返回的是普通值还是promise
                        resolvePromise(promise2,x,resolve,reject)
                    }catch (e) {
                        reject(e)
                    }
                },0)

            }else if(this.status===REJECTED){
                setTimeout(() => {
                    try {
                        let x = failedCallback(this.reason);
                        //根据返回的是普通值还是promise
                        resolvePromise(promise2,x,resolve,reject)
                    }catch (e) {
                        reject(e)
                    }
                },0)
            }else {
                //处理异步 存储对应的回调
                this.failedCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failedCallback(this.reason);
                            //根据返回的是普通值还是promise
                            resolvePromise(promise2,x,resolve,reject)
                        }catch (e) {
                            reject(e)
                        }
                    },0)
                })


                this.successCallback.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallback(this.value);
                            //根据返回的是普通值还是promise
                            resolvePromise(promise2,x,resolve,reject)
                        }catch (e) {
                            reject(e)
                        }
                    },0)
                })
            }
        });
        return promise2
    }

    static all(array) {
        let result = []
        let index = 0;
        return new myPromise((resolve,reject) => {
            function addData(key,value) {
                result[key] = value
                index++

                if(array.length === index) {
                    resolve(result)
                    console.log('ss');
                }
            }

            for (let i = 0; i < array.length; i++) {
                if(array[i] instanceof myPromise) {
                    array[i].then(value => {
                        addData(i,value)
                    }, reason => {
                        reject(reason)
                    })
                }else {
                    addData(i,array[i])
                }
            }
        })
    }

    static resolve(value) {
        if(value instanceof myPromise) {
            return value
        }else {
            return new myPromise(resolve => {
                resolve(value)
            })
        }
    }

    finally(callback) {
        return this.then(value => {
            myPromise.resolve(callback()).then(() => value)
            // callback()
        },reason => {
            // callback()
            myPromise.resolve(callback()).then(() => {throw reason})
        })
    }

    catch(failcallback) {
        return this.then(undefined,failcallback)
    }
}

function resolvePromise(promise2,x,resolve,reject) {
    if(x===promise2) {
        return reject(new TypeError('类型错误'))
    }
    if(x instanceof myPromise) {
        x.then(resolve,reject)
    }else {
        resolve(x)
    }
}

module.exports = myPromise
